﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Lari.Framework.Utility;
using Lari.Web.Utility;
using Lari.Services.Implementation;
using Lari.Services.Data;
using Lari.Services.ViewModel;
using Lari.Configuration;

namespace Lari.Web.Controllers
{

    [Authorize]
    public class UsersController : LariController
    {
        private readonly UserManagementManager _userMgr;
        //private readonly MasterManager _masterMgr;

        public UsersController(UserManagementManager userMgr)
        {
            _userMgr = userMgr;
            //_masterMgr = masterMgr;
        }

        public ActionResult Index()
        {
            var model = new UserMgrGlanceModel();
            try
            {
                if (AccessCheck.HasAccess(AccessConst.User.AdminGlance))
                {
                    model = _userMgr.GetAdminGlance();
                }
                model.IsCurrentUserHasHintQuestion = _userMgr.IsCurrentUserHasHintQuestion();
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.GlancedFialed, ex, "UserController Index");
            }
            return View(model);
        }

        #region Role Management

        [AccessFilter(AccessConst.User.ManageRole)]
        public ActionResult RoleList(int? id, int? page, string sort, string sortdir)
        {

            try
            {
                var roles = _userMgr.GetAllRoles("*");
                if (roles == null)
                    return NoDataFound;
                if (id.HasValue && id.Value > 0)
                {
                    ViewBag.id = id.Value;
                }
                ViewBag.page = page;
                ViewBag.sort = sort;
                ViewBag.sortdir = sortdir;
                return View(roles);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.RoleFetchAll, ex, "UserManagementController_Role");

            }
            return View();


        }


        //public ActionResult RoleListCompleted(int? id,int? page,string sort, string sortdir, List<Role> roles, AggregateException ex)
        //{
        //    if (ex != null)
        //    {
        //        ProcessException(MessageCode.User.RoleFetchAll, ex, "UserManagementController_Role"); 
        //        return View();
        //    }
        //    if (id.HasValue && id.Value > 0)
        //    {
        //        ViewBag.id = id.Value;
        //    }
        //    ViewBag.page = page;
        //    ViewBag.sort = sort;
        //    ViewBag.sortdir = sortdir;
        //    return View(roles);
        //}

        [ChildActionOnly]
        [OutputCache(Duration = 1, VaryByParam = "*")]
        public PartialViewResult ViewRole(int id)
        {
            Role role = null;
            try
            {
                role = _userMgr.GetCompleteRole(id);
                ViewBag.AppModules = _userMgr.GetAllModules();

            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.RoleaccessFetchFailed, ex, "UserManagementController_ViewRole");
            }

            return PartialView("ViewRole", role);
        }

        [AccessFilter(AccessConst.User.ModifyRole)]
        public ActionResult EditRole(int id)
        {
            try
            {
                var modules = _userMgr.GetAllModulesWithAccess();
                var role = _userMgr.GetCompleteRole(id);
                if (role == null)
                    return NoDataFound;

                if (modules != null)
                {
                    var model = new RoleModel(false) { Id = role.ID, Name = role.Name };
                    var mod = new List<ModuleModel>();
                    modules.ForEach(app =>
                    {
                        var mo = new ModuleModel { Id = app.ID, Name = app.Caption };
                        var accList = new List<AccessModel>();
                        foreach (var acc in app.Accesses)
                        {
                            var a = new AccessModel { Id = acc.ID, Name = acc.Name, HasAccess = false };
                            foreach (var b in role.RoleAccesses)
                            {
                                if (b.AccessId == a.Id)
                                    a.HasAccess = b.IsEnabled;

                            }
                            accList.Add(a);
                        }
                        mo.Accesses = accList;
                        mod.Add(mo);


                    });
                    model.Modules = mod;
                    return View(model);

                }
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.EditRole, ex, "UserManagementController_EditRoleCompleted");

            }
            return RedirectToAction("RoleList");





        }

        [HttpPost]
        [AccessFilter(AccessConst.User.ModifyRole)]
        public ActionResult EditRole(RoleModel role)
        {
            if (role != null)
            {
                //bool accessGranted = false;
                var findElement = role.Modules.Find(mod => mod.Accesses.Find(acc => acc.HasAccess) != null);
                if (findElement == null)
                {
                    AddErrorMessage(MessageCode.User.NoAccessSelected);
                    return View(role);
                }

            }
            try
            {
                _userMgr.SaveRole(role);
                AddInfoMessage(MessageCode.Generic.DataSaved);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.EditRoleFailed, ex, "CoreController_EditRole");
            }

            return View(role);
        }

        [AccessFilter(AccessConst.User.CreateRole)]
        public ActionResult NewRole()
        {

            var model = new RoleModel(false);
            try
            {
                var modules = _userMgr.GetAllModulesWithAccess();
                var mod = new List<ModuleModel>();
                modules.ForEach(app =>
                {
                    var mo = new ModuleModel { Id = app.ID, Name = app.Caption };
                    var accList = app.Accesses.Select(acc => new AccessModel { Id = acc.ID, Name = acc.Name, HasAccess = false }).ToList();
                    mo.Accesses = accList;
                    mod.Add(mo);
                });
                model.Modules = mod;

            }
            catch (Exception ex)
            {

                ProcessException(MessageCode.User.EditRoleFailed, ex, "CoreController_NewRole");
            }
            return View(model);
        }

        [HttpPost]
        [AccessFilter(AccessConst.User.CreateRole)]
        public ActionResult NewRole(RoleModel role)
        {
            if (role != null)
            {
                //bool accessGranted = false;
                var findElement = role.Modules.Find(mod => mod.Accesses.Find(acc => acc.HasAccess) != null);
                if (findElement == null)
                {
                    AddErrorMessage(MessageCode.User.NoAccessSelected);
                    return View(role);
                }

            }
            try
            {
                _userMgr.SaveRole(role);
                AddInfoMessage(MessageCode.Generic.DataSaved);
                return RedirectToAction(ActionConst.Users.RoleList, ControllerConst.Users);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.EditRoleFailed, ex, "CoreController_NewRole_post");

            }
            return View(role);

        }

        #endregion

        #region Add Employee

        [AccessFilter(AccessConst.User.AddEmployee)]
        public ActionResult AddEmployee()
        {
            return View(new EmployeeModel());
        }

        [HttpPost]
        [AccessFilter(AccessConst.User.AddEmployee)]
        public ActionResult AddEmployee(EmployeeModel model)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return View(model);
                }
                model.Location = 1;
                var empId = _userMgr.SaveEmployee(model);
                AddInfoMessage(MessageCode.Generic.DataSaved);
                return RedirectToAction(ActionConst.Users.ViewEmployee, ControllerConst.Users, new { id = empId });

            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.AddUserFailed, ex, "UserManagementController AddEmployee post");
            }

            return View(model);
        }

        #endregion

        #region view Employee
        [AccessFilter(AccessConst.User.ViewEmployee)]
        public ActionResult ViewEmployee(int id)
        {
            var view = new EmployeeModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;

                view = model.ConvertToViewModel();
                if (view.IsDOBCulculated)
                {
                    if (view.DOB != null) view.Age = (DateTime.Now - view.DOB.Value).Days / 365;
                }
                if (model.User != null)
                {
                    view.User = model.User.ConvertToViewModel();
                }
                return View(view);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ViewEmployeeFailed, ex, "UserManagementController ViewEmployee");
            }
            return View(view);
        }

        #endregion

        #region Edit Employee

        [AccessFilter(AccessConst.User.EditEmployee)]
        public ActionResult EditEmployee(int id)
        {
            var view = new EmployeeModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;
                view = model.ConvertToViewModel();
                if (view.IsDOBCulculated)
                {
                    if (view.DOB != null) view.Age = (DateTime.Now - view.DOB.Value).Days / 365;
                    view.DOB = null;
                }


                return View(ActionConst.Users.AddEmployee, view);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.EditEmployeeFailed, ex, "UserManagementController EditEmployee");
            }
            return View(ActionConst.Users.AddEmployee, view);
        }

        [AccessFilter(AccessConst.User.EditEmployee)]
        [HttpPost]
        public ActionResult EditEmployee(EmployeeModel model)
        {

            try
            {
                if (!ModelState.IsValid)
                {
                    return View(ActionConst.Users.AddEmployee, model);
                }
                model.Location = 1;
                var empId = _userMgr.SaveEmployee(model);
                AddInfoMessage(MessageCode.Generic.DataSaved);
                return RedirectToAction(ActionConst.Users.ViewEmployee, ControllerConst.Users, new { id = empId });
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.EditUserfailed, ex, "UserManagementController EditEmployee post");
            }

            return View(ActionConst.Users.AddEmployee, model);



        }

        #endregion

        #region Create login user

        [AccessFilter(AccessConst.User.AddEmployee)]
        public ActionResult CreateLoginUser(int id)
        {
            var view = new UserMapModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;
                var empModel = model.ConvertToViewModel();
                view.EmpId = empModel.ID;
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }
                if (model.User != null)
                {
                    view.UserIsMapped = true;

                }
                view.EmployeeModel = empModel;

                return View(view);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ViewEmployeeFailed, ex, "UserManagementController CreateLoginUser");
            }
            return View(view);
        }

        [HttpPost]
        [AccessFilter(AccessConst.User.AddEmployee)]
        public ActionResult CreateLoginUser(UserMapModel model)
        {
            try
            {
                var empModel = _userMgr.Employee(model.EmpId).ConvertToViewModel();
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                model.EmployeeModel = empModel;
                if (!ModelState.IsValid)
                {
                    return View(model);
                }
                _userMgr.SaveUser(model.EmpId, model.UserId, model.Password, model.RoleId);
                AddInfoMessage(MessageCode.Generic.DataSaved);
                return RedirectToAction(ActionConst.Users.ViewEmployee, new { id = model.EmpId });
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.CreateUserFailed, ex, "UserController CreateLoginUser post");
            }
            return View(model);
        }

        #endregion

        #region Reset password
        [AccessFilter(AccessConst.User.ResetPassword)]
        public ActionResult ResetPassword(int id)
        {
            var view = new UserMapModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;
                var empModel = model.ConvertToViewModel();
                view.EmpId = empModel.ID;
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }
                if (model.User != null)
                {
                    view.UserIsMapped = true;
                    view.RoleId = model.User.RoleID;
                    view.UserId = model.User.UserId;
                }
                else
                {
                    view.UserIsMapped = false;
                }
                view.EmployeeModel = empModel;

            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ViewEmployeeFailed, ex, "UserController ResetPassword");
            }
            return View(view);
        }

        [HttpPost]
        [AccessFilter(AccessConst.User.ResetPassword)]
        public ActionResult ResetPassword(UserMapModel model)
        {
            try
            {
                var empModel = _userMgr.Employee(model.EmpId).ConvertToViewModel();
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                model.EmployeeModel = empModel;
                if (!ModelState.IsValid)
                {
                    return View(model);
                }
                _userMgr.ChangePassword(model.UserId, model.Password);
                AddInfoMessage(MessageCode.Generic.DataSaved);
                return RedirectToAction(ActionConst.Users.ViewEmployee, new { id = model.EmpId });
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.CreateUserFailed, ex, "UserController ResetPassword post");
            }
            return View(model);
        }
        #endregion

        #region Make Inactive
        [AccessFilter(AccessConst.User.DeActivate)]
        public ActionResult MakeInActive(int id)
        {
            var view = new UserMapModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;
                var empModel = model.ConvertToViewModel();
                view.EmpId = empModel.ID;
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                view.EmployeeModel = empModel;

            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ViewEmployeeFailed, ex, "UserController MakeInActive");
            }
            return View(view);
        }
        [AccessFilter(AccessConst.User.DeActivate)]
        [HttpPost]
        public ActionResult MakeInActive(UserMapModel model)
        {
            try
            {
                _userMgr.ChangeEnployeeActivStatus(model.EmpId, false);
                AddInfoMessage(MessageCode.Generic.DeactivationDone);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.DeActivateFailed, ex, "UserController MakeInActive");
            }
            return RedirectToAction(ActionConst.Users.ViewEmployee, new { id = model.EmpId });
        }


        #endregion

        #region Make active
        [AccessFilter(AccessConst.User.Activate)]
        public ActionResult MakeActive(int id)
        {
            var view = new UserMapModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;
                var empModel = model.ConvertToViewModel();
                view.EmpId = empModel.ID;
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                view.EmployeeModel = empModel;

            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ViewEmployeeFailed, ex, "UserController MakeActive");
            }
            return View(view);
        }

        [AccessFilter(AccessConst.User.Activate)]
        [HttpPost]
        public ActionResult MakeActive(UserMapModel model)
        {
            try
            {
                _userMgr.ChangeEnployeeActivStatus(model.EmpId, true);
                AddInfoMessage(MessageCode.Generic.ActivationDone);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ActivationFailed, ex, "UserController MakeActive");
            }
            return RedirectToAction(ActionConst.Users.ViewEmployee, new { id = model.EmpId });
        }

        #endregion

        #region Change Role
        [AccessFilter(AccessConst.User.ChangeRole)]
        public ActionResult ChangeRole(int id)
        {
            var view = new UserMapModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;
                var empModel = model.ConvertToViewModel();
                view.EmpId = empModel.ID;
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }
                if (model.User != null)
                {
                    view.UserIsMapped = true;
                    view.RoleId = model.User.RoleID;
                    view.UserId = model.User.UserId;
                }
                else
                {
                    view.UserIsMapped = false;
                }
                view.EmployeeModel = empModel;

            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ViewEmployeeFailed, ex, "UserController ChangeRole");
            }
            return View(view);
        }
        [AccessFilter(AccessConst.User.ChangeRole)]
        [HttpPost]
        public ActionResult ChangeRole(UserMapModel model)
        {
            try
            {
                var empModel = _userMgr.Employee(model.EmpId).ConvertToViewModel();
                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                model.EmployeeModel = empModel;
                if (model.RoleId == 0 || string.IsNullOrWhiteSpace(model.UserId) || model.EmpId == 0)
                {
                    return View(model);
                }
                _userMgr.ChangeRole(model.EmpId, model.RoleId);
                AddInfoMessage(MessageCode.User.RoleChangeSuccess);
                return RedirectToAction(ActionConst.Users.ViewEmployee, new { id = model.EmpId });
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ChangeRoleFailed, ex, "UserController ChangeRole post");
            }
            return View(model);
        }

        #endregion

        #region Manage consultant specialization
        [AccessFilter(AccessConst.User.ManageSpecialization)]
        public ActionResult ConsultantSpecialization(int id)
        {

            var view = new ConsultantSpecializationModel();
            try
            {
                var model = _userMgr.Employee(id);
                if (model == null)
                    return NoDataFound;
                var empModel = model.ConvertToViewModel();

                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                view.Employee = empModel;
                var allSpecializationForDept = _userMgr.SepecializationForDepartment(view.Employee.DepartmentId);
                if (allSpecializationForDept != null && allSpecializationForDept.Count > 0)
                {
                    view.DepartmentSpecialization = new List<LookUpModel<int, string>>();
                    allSpecializationForDept.OrderBy(s => s.Name).ToList().ForEach(s => view.DepartmentSpecialization.Add(new LookUpModel<int, string> { IsSelected = false, Key = s.ID, Value = s.Name }));

                    var consulttantSpecialization = _userMgr.SpecializationForConsultant(view.Employee.ID);

                    view.ConsultantSpecialization = new List<LookUpModel<int, string>>();
                    consulttantSpecialization.ForEach(s => view.ConsultantSpecialization.Add(new LookUpModel<int, string> { IsSelected = false, Key = s.SpecialisationId, Value = s.Specialization.Name }));
                    view.RemainingDepartmentSpecialization = new List<LookUpModel<int, string>>();
                    
                    view.DepartmentSpecialization.ForEach(s=>
                                {
                                    if (!view.ConsultantSpecialization.Any(c => c.Key == s.Key))
                                    {
                                        view.RemainingDepartmentSpecialization.Add(new LookUpModel<int, string>{Key=s.Key,Value = s.Value});
                                    }
                                });
 

                    //view.RemainingDepartmentSpecialization = view.DepartmentSpecialization.SkipWhile(
                    //                    s => view.ConsultantSpecialization.Any(y => y.Key == s.Key)).ToList();

                }

                return View(view);
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ConsultantSpecializationFailed, ex, "UserController ConsultantSpecialization");
            }
            return View(view);

        }

        [HttpPost]
        [AccessFilter(AccessConst.User.ManageSpecialization)]
        public ActionResult AddConsultantSpecialization(ConsultantSpecializationModel model)
        {
            try
            {
                var data = _userMgr.Employee(model.Employee.ID);
                if (data == null)
                    return NoDataFound;
                var empModel = data.ConvertToViewModel();

                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                model.Employee = empModel;
                if (!model.RemainingDepartmentSpecialization.Any(s => s.IsSelected))
                {
                    AddErrorMessage(MessageCode.User.NoSpecializationSelectedFromDepartment);
                    return View(ActionConst.Users.ConsultantSpecialization, model);
                }
                _userMgr.AddConsultantSpecialization(model.Employee.ID,
                                                     model.RemainingDepartmentSpecialization.Where(s => s.IsSelected).
                                                         Select(z => z.Key).ToList());
                AddInfoMessage(MessageCode.User.SpecializationAddedSuccess);
                return RedirectToAction(ActionConst.Users.ConsultantSpecialization, new {id = model.Employee.ID});
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ConsultantSpecializationAddFailed, ex, "UserController AddConsultantSpecialization post");
            }
            return View(ActionConst.Users.ConsultantSpecialization, model);
        }

        [HttpPost]
        [AccessFilter(AccessConst.User.ManageSpecialization)]
        public ActionResult RemoveConsultantSpecialization(ConsultantSpecializationModel model)
        {
            try
            {
                var data = _userMgr.Employee(model.Employee.ID);
                if (data == null)
                    return NoDataFound;
                var empModel = data.ConvertToViewModel();

                if (empModel.IsDOBCulculated)
                {
                    if (empModel.DOB != null) empModel.Age = (DateTime.Now - empModel.DOB.Value).Days / 365;
                }

                model.Employee = empModel;
                if (!model.ConsultantSpecialization.Any(s => s.IsSelected))
                {
                    AddErrorMessage(MessageCode.User.NoSpecializationSelectedFromConsultant);
                    return View(ActionConst.Users.ConsultantSpecialization, model);
                }
                _userMgr.RemoveConsultantSpecialization(model.Employee.ID,
                                                     model.ConsultantSpecialization.Where(s => s.IsSelected).
                                                         Select(z => z.Key).ToList());

                AddInfoMessage(MessageCode.User.SpecializationRemovedSuccess);
                return RedirectToAction(ActionConst.Users.ConsultantSpecialization, new { id = model.Employee.ID });
            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.ConsultantSpecializationRemoveFailed, ex, "UserController AddConsultantSpecialization post");
            }
            return View(ActionConst.Users.ConsultantSpecialization, model);
        }
        #endregion

        #region Search
        [AccessFilter(AccessConst.User.Search)]
        public ActionResult Search(string search = null, int currentPage = 1)
        {
            if (string.IsNullOrWhiteSpace(search))
            {
                return View();
            }
            var model = new UserSearchModel { SearchString = search, CurrentPage = currentPage };

            try
            {
                int totalPageCount = 0;
                var searchresult = new List<EmployeesUsersViewModel>();
                var record = _userMgr.SearchEmployeesUser(search, currentPage, ref totalPageCount);
                if (record != null)
                {
                    record.ForEach(r => searchresult.Add(r.ConvertToViewModel()));
                    model.Result = searchresult;
                    model.TotalPageCount = totalPageCount;
                    var lastSerchParaCookee = new HttpCookie(CookieName.LastEmployeeUserSerch, Encryption.Encrypt(search)) { Expires = DateTime.Now.AddDays(1) };
                    Response.Cookies.Add(lastSerchParaCookee);
                }


            }
            catch (Exception ex)
            {
                ProcessException(MessageCode.User.SearchFailed, ex, "UserController Serach");
            }
            return View(model);

        }


        #endregion

       
    }
}


